From the Constructor declaration we see that last parameter is used as input into Function Builder @ViewBuilder.
In other words closure lines are used as input parameters into Method ViewBuilder.buildBlock().
This allows us to rewrite our code as: (we have omitted default parameters and provided Closure outside Parameter list)
Direct call to ViewBuilder.buildBlock()
struct ContentView: View {
var body: some View {
return VStack {
return ViewBuilder.buildBlock(Text("Hello"), Text("world!"))
}
}
}
If you Right Click on buildBlock and select Jump to definition you will see that buildBlock<C0, C1> is Generic Method
● that accepts 2 Parameters (which must conform to View Protocol)
● and returns TupleView<T> that contains Tuple with these two Views TupleView<(C0, C1)>
Declaration of buildBlock()
public static func buildBlock<C0, C1> (_ c0: C0, _ c1: C1) -> TupleView<(C0, C1)> where C0 : View, C1 : View
If you Right Click on TupleView and select Jump to definition you will see that TupleView is a simple Generic struct with a
single Property. And in our case this will be a Tuple containing our two Views (C0, C1).
Declaration of TupleView<T>
@frozen public struct TupleView<T> : View {
public var value: T
}
Since content Closure simply returns TupleView with our two Views inside the Tuple, we can now provide TupleView
directly to the VStack content parameter as: (So VStack's content Parameter contains Tuple with all of its children)
Provide TupleView to VStack content parameter
struct ContentView: View {
var body : some View {
return VStack {
TupleView( (Text("Hello"), Text("world!")) )
}
}
}